package com.lxm.ymcc.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.common.Client;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.lxm.ymcc.domain.AlipayInfo;
import com.lxm.ymcc.domain.PayFlow;
import com.lxm.ymcc.domain.PayOrder;
import com.lxm.ymcc.dto.AlipayNotifyDto;
import com.lxm.ymcc.dto.PayDto;
import com.lxm.ymcc.dto.PayResultVo;
import com.lxm.ymcc.service.IAlipayInfoService;
import com.lxm.ymcc.service.IPayOrderService;
import com.lxm.ymcc.service.IPayService;
import com.lxm.ymcc.util.AssertUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class PayServiceImpl implements IPayService {

    /*
       1.根据订单号 查询支付单
       2.调用支付宝下单的方法
           2.1 导包
           2.2 调用方法下单
           Factory.Payment.Page().pay("ymcc", "2206518138", "100.00", "http://localhost:6002/pay.success.html");
           2.3  返回的是一个form表单
           2.4  把表单写出到页面上--拉起收银台
    */
    @Autowired
    private IPayOrderService payOrderService;
    @Autowired
    private IAlipayInfoService alipayInfoService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Override
    public String pay(PayDto payDto) {
        PayOrder payOrder = payOrderService.selectOneSn(payDto.getOrderNo());
        AssertUtil.isNotNull(payOrder,"非法的请求");
        AssertUtil.isEqualsTrim(payOrder.getPayStatus(),0,"订单已经处理");
        // 1. 设置参数（全局只需设置一次）
        //去数据库查询
        AlipayInfo alipayInfo = alipayInfoService.selectById(2L);
        //判定回调的url
        String returnUrl = payDto.getCallUrl()!=null?payDto.getCallUrl():alipayInfo.getReturnUrl();

        try {
            Factory.setOptions(getOptions(alipayInfo));
            //下单
            AlipayTradePagePayResponse response = Factory.Payment.Page().pay(payOrder.getSubject(), payOrder.getOrderNo(), payOrder.getAmount().toString(), returnUrl);

            payOrder.setPayStatus(1);//设置为支付中
            payOrder.setUpdateTime(new Date());
            payOrderService.updateById(payOrder);

            return  response.getBody();//拉起收银台的form 表单
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "";
    }

 /*
    要做哪些事情？
            1.接收支付宝异步回调参数【定义一个类型接收】
            2.验证签名【实例代码】
            3.验证支付状态--》根据订单号查询数据库，确认数据库数据是还未处理
            4.更改支付单状态，生成支付流水
            5.更新订单状态，【ymcc-order】--feign
            6.维护学生的购买的课程表【ymcc-course】--feign
  */

    @Override
    public String notifyAlipay(AlipayNotifyDto alipayNotifyDto) {

        //2.验证签名【实例代码】
        /*
            2.1 接收到的数据  转换为一个map
         */
        //把对象转换为map
        Map map = JSON.parseObject(JSON.toJSONString(alipayNotifyDto), Map.class);
        Boolean aBoolean = null;
        try {
            aBoolean = Factory.Payment.Common().verifyNotify(map);
            if (!aBoolean) return "fail";
        } catch (Exception e) {
            e.printStackTrace();
            return "fail";
        }
        // 3.验证支付状态--》根据订单号查询数据库，确认数据库数据是还未处理



        /*
            3.1 根据订单号查询支付单
         */
        //我们系统里面的订单号
        String orderNo = alipayNotifyDto.getOut_trade_no();
        PayOrder payOrder = payOrderService.selectOneSn(orderNo);

        //发起支付宝的退款
        if (payOrder.getPayStatus().equals(PayOrder.PAY_TIMEOUT_CANCEL)){
            try {
                Factory.Payment.Common().refund(orderNo,alipayNotifyDto.getTotal_amount());
            } catch (Exception e) {
                e.printStackTrace();
                log.info("支付宝退款失败：{}",e.getMessage());
            }
        }


        //根据订单号查找支付单，状态不正确
        if (payOrder==null||payOrder.getPayStatus()!=PayOrder.PAY_PAYMENT) return "fail";

        if (alipayNotifyDto.getTrade_status().equals(AlipayNotifyDto.TRADE_FINISHED)||
                alipayNotifyDto.getTrade_status().equals(AlipayNotifyDto.TRADE_SUCCESS)
        ) {
            // 4.更改支付单状态，生成支付流水
            Date now = new Date();
            payOrder.setPayStatus(PayOrder.PAY_SUCCESS);
            payOrder.setUpdateTime(now);
            //更新数据库
            //payOrderService.updateById(payOrder);
        /*
          生成支付流水
         */
            PayFlow payFlow = new PayFlow();
            payFlow.setNotifyTime(now);
            payFlow.setSubject(payOrder.getSubject());
            payFlow.setOutTradeNo(alipayNotifyDto.getOut_trade_no());
            payFlow.setTotalAmount(new BigDecimal(alipayNotifyDto.getTotal_amount()));
            payFlow.setTradeStatus(alipayNotifyDto.getTrade_status());


            Map<String,Object> resMap = new HashMap<>();
            resMap.put("payOrder",payOrder);
            resMap.put("payFlow",payFlow);

            /*
                message:投递到mq里面的消息
                5.更新订单状态，【ymcc-order】--feign --订单号
                6.维护学生的购买的课程表【ymcc-course】--feign  用户id 、订单号、课程id
             */
            PayResultVo payResultVo = new PayResultVo(payOrder.getOrderNo(),payOrder.getExtParams());

            Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(payResultVo)).build();
            TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(
                    "tx-payresult-producer",
                    "payresult-topic:payresult-tags", message,
                    resMap);
            if (!sendResult.getLocalTransactionState().equals(LocalTransactionState.COMMIT_MESSAGE)) {
                return "fail";
            }
        }


        return "success";
    }
    private Config getOptions(AlipayInfo alipayInfo) {
        Config config = new Config();
        config.protocol = alipayInfo.getProtocol();
        config.gatewayHost = alipayInfo.getGatewayHost();
        config.signType = alipayInfo.getSignType();
        config.appId = alipayInfo.getAppId();
        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
        config.merchantPrivateKey = alipayInfo.getMerchantPrivateKey();
        //注：证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径，优先从文件系统中加载，加载失败后会继续尝试从CLASS_PATH中加载
        config.alipayPublicKey = alipayInfo.getAlipayPublicKey();
        //可设置异步通知接收服务地址（可选）
        config.notifyUrl = alipayInfo.getNotifyUrl();
        //可设置AES密钥，调用AES加解密相关接口时需要（可选）
        config.encryptKey = "aa4BtZ4tspm2wnXLb1ThQA==";
        return config;
    }
}
